package com.probiz.estore.sales.service.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;

import com.probiz.estore.catalog.service.GiftCategoryManager;
import com.probiz.estore.common.model.catalog.GiftCategory;
import com.probiz.estore.common.model.order.SalesOrder;
import com.probiz.estore.common.model.sales.Gift;
import com.probiz.estore.common.service.OrderService;
import com.probiz.estore.core.search.SearchCriteria;
import com.probiz.estore.core.service.impl.GenericManagerImpl;
import com.probiz.estore.core.util.ContextUtil;
import com.probiz.estore.core.util.I18nUtil;
import com.probiz.estore.customer.service.FavoriteManager;
import com.probiz.estore.customer.service.MembershipManager;
import com.probiz.estore.exception.OutOfStockException;
import com.probiz.estore.sales.dao.GiftDao;
import com.probiz.estore.sales.model.GiftFullyModel;
import com.probiz.estore.sales.model.GiftSearchCriteria;
import com.probiz.estore.sales.service.GiftManager;
import com.probiz.estore.sales.util.GenerateCodeUtil;


/**
 * Manager implementation for Gift, responsible for business processing, and communicate between web and persistence layer.
 */
public class GiftManagerImpl extends GenericManagerImpl<Gift> implements GiftManager {
	public static Short			DELETE_STATUS_PHYSICAL	= 1;	// 物理删除成功
	public static Short			DELETE_STATUS_LOGICAL	= -1;	// 逻辑删除成功，即归档成功
	public static Short			DELETE_STATUS_FALSE		= 0;	// 删除不成功

	private GiftDao				giftDao					= null;
	private GiftCategoryManager	giftCategoryManager		= null;
	private FavoriteManager		favoriteManager			= null;
	private MembershipManager	membershipManager		= null;

	public void setMembershipManager(MembershipManager membershipManager) {
		this.membershipManager = membershipManager;
	}

	/**
	 * @param giftDao
	 *            the giftDao to set
	 */
	public void setGiftDao(GiftDao giftDao) {
		this.giftDao = giftDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.core.service.impl.GenericManagerImpl#initManager()
	 */
	@Override
	protected void initManager() {
		dao = giftDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.core.service.impl.GenericManagerImpl#preDelete(java.lang.Object)
	 */
	@Override
	protected void preDelete(Gift entity) {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.core.service.impl.GenericManagerImpl#preSave(java.lang.Object)
	 */
	@Override
	protected void preSave(Gift entity) {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#searchByCriteriaForController(com.probiz.estore.sales.model.GiftSearchCriteria,
	 *      com.probiz.estore.core.search.SearchCriteria)
	 */
	public List<Gift> searchByCriteriaForController(
			GiftSearchCriteria giftSearchCriteria, SearchCriteria searchCriteria) {
		if (searchCriteria.getPageNo() < 1) // 如果是翻页过前，就拿第一页就可以。
		{
			searchCriteria.changePaging(1, searchCriteria.getPageSize());
		}
		List<Gift> result = searchByCriteria(giftSearchCriteria, searchCriteria);
		if (result == null || result.size() == 0) {
			if (searchCriteria.getPageNo() > searchCriteria.getTotalPageCount()) // 如果是翻页前，就拿最后一页就可以。
			{
				searchCriteria.changePaging(searchCriteria.getTotalPageCount(),
						searchCriteria.getPageSize());
				result = searchByCriteria(giftSearchCriteria, searchCriteria);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#searchByCriteria(com.probiz.estore.sales.model.GiftSearchCriteria,
	 *      com.probiz.estore.core.search.SearchCriteria)
	 */
	public List<Gift> searchByCriteria(GiftSearchCriteria giftSearchCriteria,
			SearchCriteria searchCriteria) {
		return giftDao.searchByCriteria(giftSearchCriteria, searchCriteria);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#getGiftByGiftCode(java.lang.String)
	 */
	public Gift getGiftByGiftCode(String giftCode) {
		return giftDao.getUniqueByProperty("giftCode", giftCode);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#saveFully(com.probiz.estore.sales.model.GiftFullyModel)
	 */
	public Map<String, Object> saveFully(GiftFullyModel model) throws Exception {
		Map<String, Object> returnMsgs = new HashMap<String, Object>();
		Gift gift = model.getGift();

		// start:设置礼品编码并检查
		if (StringUtils.isBlank(gift.getGiftCode())) {
			boolean isCodeAvailable = false;
			do {
				String giftCode = GenerateCodeUtil.generateCode("G", 5);
				Long size = getSizeByGiftCodeByNotGiftId(giftCode, gift
						.getGiftId());
				if (size == 0) {
					// 该礼品编码可用
					isCodeAvailable = true;
					gift.setGiftCode(giftCode);
				}
			} while (!isCodeAvailable);
		} else {
			// 用getSizeByGiftCodeByNotGiftId而不用getGiftByGiftCode的原因在于调用后者的时候会有update操作，造成数据库有两个相同code的礼品，出错
			Long size = getSizeByGiftCodeByNotGiftId(gift.getGiftCode(), gift
					.getGiftId());

			if (size >= 1) {
				// 礼品编码重复
				returnMsgs.put("error", I18nUtil.getInstance().getMessage(
						"gift.giftCode.repeated"));
				evict(gift); // 必须把gift evict出session 否则会有update操作
				return returnMsgs;
			}
		}
		// end:设置礼品编码并检查

		// start:保存主体
		if (null == gift.getId()) {
			// start:更新礼品目录信息
			updateGiftCategoryItemCount(gift.getCategoryId(), 1, 1);
			// end:更新礼品目录信息
		} else {
		}
		if (gift.getMinOrderQuantity() == null) {
			gift.setMinOrderQuantity(1);
		}
		if (gift.getPrice() == null) {
			gift.setPrice(new BigDecimal(0));
		}
		if (gift.getKind() == null) {
			// 礼品默认是实体
			gift.setKind(Gift.GIFTKIND_GIFT);
		}
		// end:保存主体

		giftDao.save(gift);

		return returnMsgs;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#getSizeByGiftCodeByNotGiftId(java.lang.String,
	 *      java.lang.Integer)
	 */
	public Long getSizeByGiftCodeByNotGiftId(String giftCode, Integer giftId) {
		return giftDao.getSizeByGiftCodeByNotGiftId(giftCode, giftId);
	}

	/**
	 * 更新礼品目录的礼品数量,包括其上面的祖辈目录
	 * 
	 * @param categoryId
	 *            礼品目录id
	 * @param itemCount
	 *            要改变的数量，可正可负
	 * @param activeItemCount
	 *            要改变的激活数量，可正可负
	 */
	private void updateGiftCategoryItemCount(Integer categoryId,
			Integer itemCount, Integer activeItemCount) {
		GiftCategory giftCategory = giftCategoryManager.getById(categoryId);
		do {

			giftCategory.setItemCount(giftCategory.getItemCount().intValue()
					+ itemCount.intValue());
			giftCategory.setActiveItemCount(giftCategory.getActiveItemCount()
					.intValue()
					+ activeItemCount.intValue());
			giftCategoryManager.save(giftCategory);
			giftCategory = giftCategory.getParent();

		} while (null != giftCategory);

	}

	public void setGiftCategoryManager(GiftCategoryManager giftCategoryManager) {
		this.giftCategoryManager = giftCategoryManager;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#deleteFully(com.probiz.estore.common.model.sales.Gift)
	 */
	public short deleteFully(Gift gift) {
		OrderService orderService = (OrderService) ContextUtil.getSpringBeanById("orderService");
		short orderHistoryStatus = orderService.getGiftCircsInSalesOrder(gift.getGiftId());
		if (orderHistoryStatus == (short) 2) {
			// case:不存在任何订单，物理删除

			// 删除收藏夹
			// favoriteManager.deleteFavoriteGifts(gift.getGiftId());

			deleteById(gift.getGiftId());
			if (gift.getStatus().shortValue() == Gift.STATUS_ACTIVE
					.shortValue()) {
				updateGiftCategoryItemCount(gift.getCategoryId(), -1, -1);
			} else {
				updateGiftCategoryItemCount(gift.getCategoryId(), -1, 0);
			}
			return DELETE_STATUS_PHYSICAL;
		} else if (orderHistoryStatus == (short) 1) {
			// case:存在处理中的订单，不允许删除
			return DELETE_STATUS_FALSE;
		} else if (orderHistoryStatus == (short) 0) {
			// case:仅存在在已经归档的订单，逻辑删除，变成归档状态
			if (gift.getStatus().shortValue() == Gift.STATUS_ACTIVE
					.shortValue()) {
				gift.setStatus(Gift.STATUS_LOGICAL_DELETED);
				giftDao.save(gift);
				updateGiftCategoryItemCount(gift.getCategoryId(), -1, -1);
			} else if (gift.getStatus().shortValue() == Gift.STATUS_LOGICAL_DELETED
					.shortValue()) {
				// 本身已经是已归档 do nothing
			} else {
				gift.setStatus(Gift.STATUS_LOGICAL_DELETED);
				giftDao.save(gift);
				updateGiftCategoryItemCount(gift.getCategoryId(), -1, 0);
			}

			return DELETE_STATUS_LOGICAL;
		}
		return DELETE_STATUS_FALSE;
	}

	public void setFavoriteManager(FavoriteManager favoriteManager) {
		this.favoriteManager = favoriteManager;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#getGiftIdByUri(java.lang.String)
	 */
	public Integer getGiftIdByUri(String uri) {
		String giftId = uri.substring(uri.lastIndexOf("/") + 1, uri
				.lastIndexOf("."));
		giftId = giftId.substring("item".length());
		return Integer.valueOf(giftId);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#getUriByGift(com.probiz.estore.common.model.sales.Gift)
	 */
	public String getUriByGift(Gift gift) {
		StringBuffer url = new StringBuffer();
		url.append("/gift");
		for (GiftCategory giftCategory : giftCategoryManager
				.getNavigationCategories(gift.getCategoryId())) {
			url.append("-");
			url.append(giftCategory.getCategoryCode());
		}
		url.append("/item");
		url.append(gift.getGiftId().toString());
		url.append(".html");
		return url.toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#getGiftJSONDataForFront(com.probiz.estore.common.model.sales.Gift)
	 */
	public JSONObject getGiftJSONDataForFront(Gift gift) {
		JSONObject jsonGift = new JSONObject();
		JSONArray jsonSkuList = new JSONArray();
		jsonGift.put("minOrderQuantity",
				(gift.getMinOrderQuantity() == null) ? 1 : gift
						.getMinOrderQuantity());
		jsonGift.put("maxOrderQuantity",
				(gift.getMaxOrderQuantity() == null) ? 1 : gift
						.getMaxOrderQuantity());
		jsonGift.put("salesMeasureUnitName", gift.getWeightMeasureUnitName());
		jsonGift.put("giftId", gift.getGiftId());
		jsonGift.put("giftCode", gift.getGiftCode());
		jsonGift.put("giftName", gift.getGiftName());
		jsonGift.put("allocatedQuantity", gift.getAllocatedQuantity());
		jsonGift.put("quantityOnHand", gift.getQuantityOnHand());
		jsonGift.put("membership", gift.getMembership());
		jsonGift.put("imageUrl", gift.getImageUrl());

		return jsonGift;
	}

	public Gift getGiftPojoByGiftCode(String giftCode) {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doAllocateStock(com.probiz.estore.common.model.sales.Gift,
	 *      java.lang.Integer)
	 */
	public Integer[] doAllocateStock(Gift gift, Integer quantity)
			throws OutOfStockException {

		Integer inventory = gift.getQuantityOnHand();
		if (inventory == null || inventory >= quantity) {
			// 如果是无限库存或者可售库存大于要分配数量

			Gift _gift = gift;
			_gift.setAllocatedQuantity(gift.getAllocatedQuantity() + quantity);

			save(_gift);
			return new Integer[] { quantity, 0 };
		} else {
			// 没有足够的库存直接抛出异常
			throw new OutOfStockException(gift, gift.getQuantityOnHand());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doCancelAllocateStock(com.probiz.estore.common.model.sales.Gift,
	 *      java.lang.Integer)
	 */
	public void doCancelAllocateStock(Gift gift, Integer quantity) {
		Gift _gift = gift;
		_gift.setAllocatedQuantity(_gift.getAllocatedQuantity() - quantity);

		save(_gift);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doReleaseStock(com.probiz.estore.common.model.sales.Gift,
	 *      java.lang.Integer)
	 */
	public void doReleaseStock(Gift gift, Integer quantity) {
		Gift _gift = gift;
		_gift.setAllocatedQuantity(_gift.getAllocatedQuantity() - quantity);
		if (_gift.getQuantityOnHand() != null) {
			_gift.setQuantityOnHand(_gift.getQuantityOnHand() - quantity);
		}

		save(_gift);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#getMembershipIdsToMembershipName(com.probiz.estore.common.model.sales.Gift)
	 */
	public String getMembershipIdsToMembershipName(Gift gift) {
		if (gift == null)
			return "";
		String[] membershipIds = gift.getMembership().split(",");
		String membershipName = "";
		for (String shipIds : membershipIds) {
			membershipName += membershipManager.getById(
					Integer.valueOf(shipIds)).getMembershipName()
					+ "  ";
		}
		gift.setMembershipNames(membershipName.substring(0, membershipName
				.length() - 1));
		return gift.getMembershipNames();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doAllocateGift(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.sales.Gift, java.lang.Integer)
	 */
	public Integer[] doAllocateGift(SalesOrder salesOrder, Gift gift,Integer quantity) throws OutOfStockException {
		if(gift.getAvailableQuantity() == null || gift.getAvailableQuantity() >= quantity){
			gift.setAllocatedQuantity(gift.getAllocatedQuantity() + quantity);
			save(gift);
		}
		return new Integer[]{quantity,0};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doCanCelAllocateGift(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.sales.Gift, java.lang.Integer)
	 */
	public void doCanCelAllocateGift(SalesOrder salesOrder,Gift gift, Integer quantity){
		gift.setAllocatedQuantity(gift.getAllocatedQuantity() - quantity);
		save(gift);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doShipGift(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.sales.Gift, java.lang.Integer)
	 */
	public void doReleaseGift(SalesOrder salesOrder,Gift gift, Integer quantity){
		if(gift.getQuantityOnHand() != null){
			gift.setQuantityOnHand(gift.getQuantityOnHand()-quantity);
		}
		gift.setAllocatedQuantity(gift.getAllocatedQuantity()-quantity);
		save(gift);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.sales.service.GiftManager#doAllocateGift4OrderAction(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.sales.Gift, java.lang.Integer)
	 */
	public Integer[] doAllocateGift4OrderAction(SalesOrder salesOrder,
			Gift gift, Integer quantity) {
		if(gift.getAvailableQuantity() == null || gift.getAvailableQuantity() >= quantity){
			gift.setAllocatedQuantity(gift.getAllocatedQuantity() + quantity);
			save(gift);
		}
		return new Integer[]{quantity,0};
	}
	
	public Gift getGiftById(Integer giftId){
		return giftDao.getGiftById(giftId);
	}
}
